//@author A0096723X
///@class EntriesManager
///@Description This class is the executor of the BOT program.
///				Bot handles the following operations
///				1. Based on user command, different functions of EntriesManager are called
///				2. EntriesManager maintains a set of vector, and edits them accordingly
///				3. The vectors are sorted according to display format, and returned as a vector<vector<pair<string,string>,format>>
///				4. getCount returns the number of different types of entries, overdue, today, tasks, events.
///Add, Delete, Edit, Display, Search, SearchDate, SearchWeek, getCount

#ifndef ENTRIESMANAGER_H
#define ENTRIESMANAGER_H

#include<string>
#include<vector>
#include<stack>
#include <sstream>
#include <algorithm>

#include <exception>
#include <assert.h>

#include <libqxt-Qt5\include\QxtCore\qxtloggerengine.h>
#include <libqxt-Qt5\include\QxtCore\qxtlogger.h>
#include <libqxt-Qt5\include\QxtCore\QxtLogger>
#include <libqxt-Qt5\include\QxtCore\QxtBasicFileLoggerEngine>
#include <libqxt-Qt5\include\QxtCore\QxtBasicSTDLoggerEngine>

#include "Entry.h"
#include "EntriesSorter.h"
#include "EntriesDisplay.h"
#include "CommonEnum.h"
#include "CommonUtils.h"
#include "FileManager.h"
#include "BotException.h"

using namespace std;
class EntriesManager
{
	friend class EntriesManagerITest;
	friend class EntriesManagerUTest;
	
	static const char* OUTPUT_MSG_IS_EMPTY; 
	static const char* OUTPUT_MSG_INVALID;
	static const char* OUTPUT_MSG_CONFLICT;
	static const char* OUTPUT_MSG_SUCCESS_ADD;
	static const char* OUTPUT_MSG_SUCCESS_DELETE;
	static const char* OUTPUT_MSG_SUCCESS_DISPLAY;
	static const char* OUTPUT_MSG_SUCCESS_EDIT;
	static const char* OUTPUT_MSG_SUCCESS_CLEAR;
	static const char* OUTPUT_MSG_SUCCESS_SEARCH; 
	static const char* OUTPUT_MSG_SUCCESS_SORT;
	static const char* OUTPUT_MSG_SUCCESS_UNDO; 
	static const char* OUTPUT_MSG_SUCCESS_REDO; 
	static const char* OUTPUT_MSG_SUCCESS_COMPLETED; 
	static const char* OUTPUT_MSG_SUCCESS_GENERAL;
	static const char* OUTPUT_MSG_SEARCH_NO_ITEMS;
	
	static const string _fileName;
	static const string STRING_NULL;
	static const string ENTRY_TYPE_EVENT;
	static const string ENTRY_TYPE_TASK;
	static const string OUTPUT_MSG_DEFAULT_VIEW;
	static const string OUTPUT_MSG_ALL;
	static const string OUTPUT_MSG_UNDO_STACK;
	static const string OUTPUT_MSG_REDO_STACK;
	static const string OUTPUT_MSG_LAST_COMMAND;
	static const string OUTPUT_MSG_COMPLETE;
	static const string OUTPUT_MSG_INCOMPLETE;
	static const string OUTPUT_MSG_ENTRIES;
	static const string OUTPUT_MSG_ITEMS_IN;
	static const string OUTPUT_MSG_ITEMS_UPCOMING_WEEK;

	static const QString FORMAT_DATE;
	static const QString FORMAT_TIME;
	static const QString LOG_ADD_COMMAND;
	static const QString LOG_DELETE_COMMAND;
	static const QString LOG_EDIT_COMMAND;
	static const QString LOG_UNDO_COMMAND;
	static const QString LOG_REDO_COMMAND;
	static const QString LOG_CLEAR_COMMAND;
	static const QString LOG_SET_DONE_COMMAND;
	static const QString LOG_SEARCH_COMMAND;
	static const QString LOG_SEARCH_TASK_COMMAND;
	static const QString LOG_SEARCH_EVENT_COMMAND;
	static const QString LOG_SEARCH_WEEK_COMMAND;
	static const QString LOG_SEARCH_DAY_COMMAND;
	static const QString LOG_SEARCH_STATUS_COMMAND;

	enum DISPLAY_FORMAT{
		DISPLAY_DEFAULT,
		DISPLAY_SEARCH,
		DISPLAY_SEARCH_DATE
	};
	enum MSG_TYPE{
		MSG_IS_EMPTY, 
		MSG_INVALID, 
		MSG_CONFLICT,
		MSG_SUCCESS_ADD, 
		MSG_SUCCESS_DELETE, 
		MSG_SUCCESS_DISPLAY, 
		MSG_SUCCESS_EDIT, 
		MSG_SUCCESS_CLEAR, 
		MSG_SUCCESS_SEARCH, 
		MSG_SUCCESS_SORT, 
		MSG_SUCCESS_UNDO, 
		MSG_SUCCESS_REDO, 
		MSG_SUCCESS_COMPLETED, 
		MSG_SEARCH_NO_ITEMS
	};
	enum DISPLAY_TYPE{
		DISPLAY_TYPE_ALL,
		DISPLAY_TYPE_DEFAULT
	};
	
	struct ENTRIES{
		vector<Entry*> activeEntries;
		vector<Entry*> inactiveEntries;
		vector<Entry*> conflictVector;
		DISPLAY_FORMAT currentDisplayFormat;
		Entry* newEntry;
		int currentDisplayIndex;
		QDate searchDate;
		string searchLabel;
	};
	ENTRIES _entries;
	stack<ENTRIES> _entriesHist;
	stack<ENTRIES> _entriesRedo;
	FileManager& _file;
	
	EntriesManager(FileManager& file);
	EntriesManager();
	~EntriesManager(void);
	
	bool currentDisplayIsEmpty();

	//@brief updates the storage component.
	void updateFile();

	void updateCurrentDisplayIndex();

	//@param takes in two vectors, found and notFound
	//@brief replace activeEntries with found, and appends inactive with notFound
	void updateFoundEntries(const vector<Entry*>& found, const vector<Entry*>& notFound);

	//1. Clears redo stack and updates undo stack
	//2. gets new set of Entry* vector from storage component
	//3. splits the new Entry* vector into active and inactive according to current display index
	//4. resets the newEntry and conflictVector flags.
	void generateNewVector();

	//@brief called to reset display view: combines both active and inactiveEntries, resets currentDisplayFormat flag, and filters incomplete entries
	void initEntries();

	void defaultSort();

	//@brief deletes a vector's pointers and clears the vector
	void deleteVector(vector<Entry*>&);

	//@brief clears a stack of ENTRIES
	void clearStack(stack<ENTRIES>&);

	//@brief clears all previous undos >10 steps ago
	void clearOverflowUndo();

	void validateIndex(int);
	void assignEditAttributes(Entry* &targetEntry, vector<string> entryVector, int index);
	void editStartTime(string timeString, Entry*& targetEntry, int index);
	void editStartDate(string timeString, Entry*& targetEntry, int index);
	void resetView();
	void showAll();
	void resetSearchAttributes();
	void filterStatus(bool target);
	void filterStatus();
	void checkUndoStack();
	void checkRedoStack();

	string addToEntries(Entry* newEntry);
	string removeFromEntries(int index);
	string editEntry(int index, vector<string> entryVector);
	string revertLastState();	
	string revertRedoState();
	string clearEntries();
	string setEntryDone(int index);
	string searchEntries(string target, CommonEnum::SEARCH_TYPE searchType);
	string searchEntriesTasks();
	string searchEntriesEvents();
	string searchEntriesDay(QDate, CommonEnum::SEARCH_TYPE searchType);
	string searchEntriesStatus(bool target);

	vector<Entry*> getAllEntries();
	vector<Entry*> getConflict(Entry*);

	vector<vector<CommonEnum::ReturnString>> printVectorToString();
	vector<vector<CommonEnum::ReturnString>> getDefaultString();
	vector<vector<CommonEnum::ReturnString>> getSearchString();
	vector<vector<CommonEnum::ReturnString>> getSearchDateString();

	CommonEnum::ReturnStatus sendOutputMessage(string messageDisplayed, MSG_TYPE cmd);
public:
	static EntriesManager& getInstance(FileManager*);
	static EntriesManager& getInstance();
	
	//@param	newEntry
	//			(should be validated by caller)
	//@return display vector of operation, status message of operation shows name of newEntry
	//1. Generates a new set of vector of Entry pointers, and updates the undo stack with existing vectors
	//2. Adds the newEntry to the new vector and updates txt file accordingly.
	//3. sets the _entries.newEntry flag to the newly added entry
	//4. Returns status message that name of newEntry is added.
	CommonEnum::ReturnStatus addCommand(Entry* newEntry);

	//@param	index
	//			(index should corresponding to vector position)
	//@return display vector of operation, status message include name of removedEntry
	//1. validate index
	//2. Generates a new set of vector of Entry pointers, and updates the undo stack with existing vectors
	//3. Removes the selected Entry from the new vector and updates txt file accordingly.
	//4. Returns status message that name of removedEntry is deleted.
	//5. Returns vector strings of sorted Entries.
	CommonEnum::ReturnStatus deleteCommand(int index);

	//@param	type
	//			(type should correspond to the type of display required)
	//			DISPLAY_TYPE_ALL shows all entries sorted into overdue, today, tomorrow, future
	//			DISPLAY_TYPE_DEFAULT shows uncompleted entries with same sections
	//@return display vector of entries, status message displays successful display
	//search flags are reset, and displayformat flag is set back to default display format.
	CommonEnum::ReturnStatus displayCommand(DISPLAY_TYPE);

	//@brief following two functions call displayCommand with the necessary display_type
	CommonEnum::ReturnStatus displayCommand();

	CommonEnum::ReturnStatus displayAllCommand();

	//@param	index
	//			(index corresponds to vector position of entry)
	//			entryVector
	//			(string vector that contains the attributes, assumed validated by caller, should be size 5)
	//@return	display vector of active entries, statusmessage includes name of edited entry
	//1. Validate Index
	//2. Generates a new set of vector of Entry pointers, and updates the undo stack with existing vectors
	//3. Edit the selected entry: If start attributes edited for tasks, they are converted to events
	//4. sets the newEntry flag as the edited entry.
	CommonEnum::ReturnStatus editCommand(int index, vector<string> entryVector);

	//Undo the last command.
	//1. checks if history stack is empty and throws exception if it is.
	//2. push to redo stack, and takes the top of undo stack as current state.
	//3. update the txt file
	//@return	display vector of operation, status message shows successful undo command
	CommonEnum::ReturnStatus undoCommand();

	//Redo the last command before undo
	//1. checks if history stack is empty and throws exception if it is.
	//2. push to undo stack, and takes the top of redo stack as current state.
	//3. update the txt file
	//@return display vector of operation, status message returns successful redo command
	CommonEnum::ReturnStatus redoCommand();

	//Clears the entire vector of entries
	//1. generates new set of vector
	//2. deletes the pointers held by current vector and clears the vectors
	//3. update the file
	//@return display message of operation , status message shows successful clear command
	CommonEnum::ReturnStatus clearCommand();

	//@param	index
	//			(corresponds to vector position of entry)
	//1. validates the index and throw exception if invali
	//2. generate new set of vector
	//3. updates the target entry status
	//4. update file
	//@return display vector of operation, status message includes name of target entry
	CommonEnum::ReturnStatus setDoneCommand(int index);

	//@param	target
	//			(string to be searched)
	//			searchType
	//			SEARCH_TYPE_CUMULATIVE searches the string word by word. any entry that matches any word is returned
	//			SEARCH_TYPE_DEFAULT searches exact match of the string
	//@return display vector showing all matching entries, statusmessage includes search criteria
	CommonEnum::ReturnStatus searchCommand(string target, CommonEnum::SEARCH_TYPE searchType);

	//@brief calls searchCommand with a default searchtype by overload
	CommonEnum::ReturnStatus searchCommand(string target);

	CommonEnum::ReturnStatus searchTasks();

	CommonEnum::ReturnStatus searchEvents();

	//@param	target
	//			(date to be searched)
	//			searchType
	//			SEARCH_TYPE_CUMULATIVE searches all entries to be done by the target date
	//			SEARCH_TYPE_DEFAULT searches only entries to be done on the target date
	//@return display vector showing all matching entries, statusmessage includes search criteria
	CommonEnum::ReturnStatus searchDay(QDate target, CommonEnum::SEARCH_TYPE searchType);

	//@brief overloaded function to call searchDay with default parameter.
	CommonEnum::ReturnStatus searchDay(QDate target);

	CommonEnum::ReturnStatus searchDayBefore(QDate target);

	CommonEnum::ReturnStatus searchDayPastNotDone(QDate target);

	CommonEnum::ReturnStatus searchDayNotDone(QDate target);

	//@param	target
	//			(status to be searched)
	//@return display vector showing all matching entries, statusmessage includes search criteria
	CommonEnum::ReturnStatus searchStatus(bool target);

	//@brief overload function to call searchStatus with default bool=false
	CommonEnum::ReturnStatus searchStatus();

	CommonEnum::ReturnStatus searchWeek();

	//@brief returns a count of the following groups of entries
	//Overdue, Today, Future, Tasks, Events
	CommonEnum::ReturnCount getCount();

	//@brief returns the vector of entries
	vector<Entry*> getActive();

	//@brief returns a stringlist of all entries
	QStringList getNameVect();

};
#endif